Skip to content

Compile benchmark with Dotty, fixes #29. #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 23, 2017
Merged

Conversation

olafurpg
Copy link
Contributor

@olafurpg olafurpg commented Jun 14, 2017

  • ++0.2.0-RC1 to run benchmarks with dotc instead of scalac
  • compilation/test to quickly check the setup is OK without the need to remember cli args or start slow jmh process.

@olafurpg olafurpg mentioned this pull request Jun 14, 2017
@olafurpg
Copy link
Contributor Author

I'm not sure what exactly caused the CI failure, I suspect it's Travis killing the job.

Copy link
Member

@lrytz lrytz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FOLLOW_LINKS is necessary when the corpusVersion parameter is not explicitly given through -p corpusVersion abcd123, in which case the value is "latest", which is a symlink (https://github.com/scala/compiler-benchmark/tree/master/corpus/better-files).

You say fork in run is required for running compilation/run, but the main way to execute benchmarks is through compilation/jmh:run HotScalacBenchmark, or even better by using the hot / cold aliases in sbt

I think you're right about the CI failure, it's probably a Travis timeout. For some reason the performance on travis is much lower than the previous successful run:

Before (https://travis-ci.org/scala/compiler-benchmark/builds/237376124)

[info] Iteration   1: 3221.225 ±(99.9%) 447.551 ms/op

Your run (https://travis-ci.org/scala/compiler-benchmark/builds/242931056)

[info] Iteration   1: 7541.359 ms/op

This might be due to a change on travis. Do you see comparable numbers locally?

@@ -148,7 +126,7 @@ object ScalacBenchmarkStandalone {
@BenchmarkMode(Array(SingleShotTime))
@OutputTimeUnit(TimeUnit.MILLISECONDS)
// TODO -Xbatch reduces fork-to-fork variance, but incurs 5s -> 30s slowdown
@Fork(value = 16, jvmArgs = Array("-XX:CICompilerCount=2", "-Xms2G", "-Xmx2G"))
//@Fork(value = 16, jvmArgs = Array("-XX:CICompilerCount=2", "-Xms2G", "-Xmx2G"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we cannot "just" change this now, because the results after that change would probably be no longer comparable with the measurements we made so far.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, seems this did not get added to my latest push, I have staging commit

-//@Fork(value = 16, jvmArgs = Array("-XX:CICompilerCount=2", "-Xms2G", "-Xmx2G"))
+@Fork(value = 16, jvmArgs = Array("-XX:CICompilerCount=2", "-Xms2G", "-Xmx2G"))
 class ColdScalacBenchmark extends ScalacBenchmark {
   @Benchmark
   def compile(): Unit = compileImpl()
@@ -138,7 +138,7 @@ class ColdScalacBenchmark extends ScalacBenchmark {
 @Measurement(iterations = 1, time = 30, timeUnit = TimeUnit.SECONDS)
 // @Fork triggers match error in dotty, see https://github.com/lampepfl/dotty/issues/2704
 // Comment out `@Fork` to run compilation/test with Dotty or wait for that issue to be fixed.
-//@Fork(value = 3, jvmArgs = Array("-Xms2G", "-Xmx2G"))
+@Fork(value = 3, jvmArgs = Array("-Xms2G", "-Xmx2G"))
 class WarmScalacBenchmark extends ScalacBenchmark {
   @Benchmark
   def compile(): Unit = compileImpl()
@@ -148,7 +148,7 @@ class WarmScalacBenchmark extends ScalacBenchmark {
 @OutputTimeUnit(TimeUnit.MILLISECONDS)
 @Warmup(iterations = 10, time = 10, timeUnit = TimeUnit.SECONDS)
 @Measurement(iterations = 10, time = 10, timeUnit = TimeUnit.SECONDS)
-//@Fork(value = 3, jvmArgs = Array("-Xms2G", "-Xmx2G"))
+@Fork(value = 3, jvmArgs = Array("-Xms2G", "-Xmx2G"))
 class HotScalacBenchmark extends ScalacBenchmark {
   @Benchmark
   def compile(): Unit = compileImpl()

Copy link
Contributor Author

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review @lrytz I updated the test to set corpusVersion and that fixed the FOLLOW_LINKS issue I encountered.

The // @Fork comments were not supposed to be there, although they are necessary at the moment to run compilation/test with Dotty.

While iterating on the build locally, I prefer to run compilation/test over hot -p ... since the jmh benchmarks are slow and Ctrl-c exits the sbt shell.

@@ -148,7 +126,7 @@ object ScalacBenchmarkStandalone {
@BenchmarkMode(Array(SingleShotTime))
@OutputTimeUnit(TimeUnit.MILLISECONDS)
// TODO -Xbatch reduces fork-to-fork variance, but incurs 5s -> 30s slowdown
@Fork(value = 16, jvmArgs = Array("-XX:CICompilerCount=2", "-Xms2G", "-Xmx2G"))
//@Fork(value = 16, jvmArgs = Array("-XX:CICompilerCount=2", "-Xms2G", "-Xmx2G"))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, seems this did not get added to my latest push, I have staging commit

-//@Fork(value = 16, jvmArgs = Array("-XX:CICompilerCount=2", "-Xms2G", "-Xmx2G"))
+@Fork(value = 16, jvmArgs = Array("-XX:CICompilerCount=2", "-Xms2G", "-Xmx2G"))
 class ColdScalacBenchmark extends ScalacBenchmark {
   @Benchmark
   def compile(): Unit = compileImpl()
@@ -138,7 +138,7 @@ class ColdScalacBenchmark extends ScalacBenchmark {
 @Measurement(iterations = 1, time = 30, timeUnit = TimeUnit.SECONDS)
 // @Fork triggers match error in dotty, see https://github.com/lampepfl/dotty/issues/2704
 // Comment out `@Fork` to run compilation/test with Dotty or wait for that issue to be fixed.
-//@Fork(value = 3, jvmArgs = Array("-Xms2G", "-Xmx2G"))
+@Fork(value = 3, jvmArgs = Array("-Xms2G", "-Xmx2G"))
 class WarmScalacBenchmark extends ScalacBenchmark {
   @Benchmark
   def compile(): Unit = compileImpl()
@@ -148,7 +148,7 @@ class WarmScalacBenchmark extends ScalacBenchmark {
 @OutputTimeUnit(TimeUnit.MILLISECONDS)
 @Warmup(iterations = 10, time = 10, timeUnit = TimeUnit.SECONDS)
 @Measurement(iterations = 10, time = 10, timeUnit = TimeUnit.SECONDS)
-//@Fork(value = 3, jvmArgs = Array("-Xms2G", "-Xmx2G"))
+@Fork(value = 3, jvmArgs = Array("-Xms2G", "-Xmx2G"))
 class HotScalacBenchmark extends ScalacBenchmark {
   @Benchmark
   def compile(): Unit = compileImpl()

Copy link
Contributor Author

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lrytz my numbers locally

> hot -psource=scalap -p corpusVersion=latest -w1 -f1
...
[info] Iteration   1: 1705.334 ±(99.9%) 319.245 ms/op
...

true
}
def compilerArgs =
if (source.startsWith("@")) Array(source)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that dotc @foo.args is not yet supported, see scala/scala3#2759

build.sbt Outdated
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % Test,
testOptions in Test += Tests.Argument(TestFrameworks.JUnit),
fork in (Test, test) := true,
fork in run := true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add a comment here why fork is needed? what's the use case for compilation/run anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed fork in run := true and added a brief comment explaining fork in (Test, test) := true. I can leave out the unit test from this PR if you prefer. I personally find it useful to be able to run ~compilation/test while iterating on the code. My first intuition in an unfamiliar sbt build is usually to run test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! It's fine for me to leave it in. I'll let @retronym take a look at this PR too, to me it looks very good!

build.sbt Outdated
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value,
mainClass in (Jmh, run) := Some("scala.bench.ScalacBenchmarkRunner")
libraryDependencies += {
if (isDotty.value) "ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to also use Sbt's scalaOrganization, this would allow the Typelevel compiler to "just work" (and others too :D).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that help when the artifact id is dotty-compiler?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, I opened #34 myself.

@biboudis
Copy link

biboudis commented Jul 11, 2017

scala/scala3#2819 is now merged!

olafurpg added 5 commits July 11, 2017 17:30
Note, the benchmarks currently don't actually run with Dotty because of
scala/scala3#2704.

- When `scalaVersion := "0.x"`, then "src/main/dotc" is  added to
  unmanagedSourceDirectories, otherwise "src/main/scalac" is added.
- compilation/test checks the setup is OK without the need to remember cli args.
- `fork in run` is necessary for -usejavacp to work with compilation/run
- `FileVisitOption.FOLLOW_LINKS` produces duplicate filenames, which
  causes "X is already compiled in this run" errors in Dotty.
This option seems to be necessary to run the JMH benchmarks.
This change causes the Dotty tests to fail with the error:
"object Vector in package immutable has already been compiled once
during this run".
This prevents the "object vector is already compiled in this run" error
when testing the Dotty compilation.
@olafurpg
Copy link
Contributor Author

I'll try to rebase on master tomorrow and upgrade to Dotty 0.2.0-RC1.

@olafurpg
Copy link
Contributor Author

CI is green but the logs show a NPE: https://travis-ci.org/scala/compiler-benchmark/builds/252729442#L840

java.lang.NullPointerException
[info] 	at scala.reflect.internal.util.BatchSourceFile.<init>(SourceFile.scala:111)
[info] 	at scala.tools.nsc.TreeTraverserBenchmark.setup(TreeTraverserBenchmark.scala:30)
[info] 	at scala.tools.nsc.generated.TreeTraverserBenchmark_measure_jmhTest._jmh_tryInit_f_treetraverserbenchmark0_0(TreeTraverserBenchmark_measure_jmhTest.java:338)
[info] 	at 

Should we change the CI to test dotc and scalac compilation?

@olafurpg
Copy link
Contributor Author

The NPE is not a regression from this PR, I can reproduce it on master branch and the Travis logs show the same https://travis-ci.org/scala/compiler-benchmark/builds/250716575#L820

I've updated .travis.yml to test compilation for scalac and dotc.

The micro/jmh command causes a NPE exception which kills the sbt process
with an exit code 0. This caused CI to report green even if the
compilation/test command did not run.
@olafurpg
Copy link
Contributor Author

The CI now runs compilation/test for scalac and dotc, see https://travis-ci.org/scala/compiler-benchmark/builds/252748994#L920. This PR is ready for another review.

@biboudis
Copy link

@olafurpg
Copy link
Contributor Author

@biboudis Yes, but the NPE is unrelated to this PR. It appears as well in the logs on master branch https://travis-ci.org/scala/compiler-benchmark/builds/250716575#L783

@lrytz
Copy link
Member

lrytz commented Jul 12, 2017

Ah right, we should fix that.

.travis.yml Outdated
@@ -3,7 +3,7 @@ language: scala
env:
global:

script: sbt test:compile "hot -psource=scalap -w1 -f1" "micro/jmh:run -w1 -f1"
script: sbt test:compile "hot -psource=scalap -w1 -f1" "; project compilation ; +test" "micro/jmh:run -w1 -f1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we're running test:compile and hot... only on scalac for now because @Fork still crashes dotc, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @Fork annotation issue has been fixed, I can change the CI to run dotty benchmarks in CI too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's still a comment in the diff that links to scala/scala3#2704

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the comment, the issue has been fixed and should be closed.

ctx.setSetting(ctx.settings.d, tempDir.getAbsolutePath)
ctx.setSetting(ctx.settings.language, List("Scala2"))
val compiler = new dotty.tools.dotc.Compiler
val args = compilerArgs ++ sourceFiles
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we also process extraArgs here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

olafurpg added 3 commits July 12, 2017 13:18
The long sbt command in .travis.yml was getting unwieldy. This commit
adds a `testAll` command which can easily be run locally from the sbt
shell to test the command executed in CI.
@olafurpg
Copy link
Contributor Author

olafurpg commented Jul 12, 2017

I took the liberty to move the long sbt command from .travis.yml into build.sbt. This makes it easier to reproduce the CI command locally from the sbt shell.

commands += Command.command("testAll") { s =>
"test:compile" ::
"compilation/test" ::
"hot -psource=scalap -wi 1 -i 1 -f1" ::
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note. I bumped down the warmup iterations from 10 to 1 to make the tests run faster. The benchmark numbers on Travis are too unreliable anyways.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

commands += Command.command("testAll") { s =>
"test:compile" ::
"compilation/test" ::
"hot -psource=scalap -wi 1 -i 1 -f1" ::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


commands += Command.command("testAll") { s =>
"test:compile" ::
"compilation/test" ::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be done on dotty too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is done in Dotty as well, see L14.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+compilation/test would not run on Dotty because it uses crossScalaVersions from the root project. Alternatives are

  • project compilation; +test ; project compiler-benchmark
  • add the sbt-doge plugin and run such compilation/test
  • add 0.2.0-RC1 to compiler-benchmark/crossScalaVersions, but that would be incorrect.

I opted for duplication since it's the dumbest solution.

Copy link
Member

@lrytz lrytz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks a lot for your work! I'll leave it open for @retronym (he's out this week).

@olafurpg
Copy link
Contributor Author

Cool. I leave for vacation next week Wednesday so hopefully we can get this in before then :)

@biboudis biboudis mentioned this pull request Aug 15, 2017
7 tasks
@olafurpg
Copy link
Contributor Author

Ping. Any update on this?

@olafurpg
Copy link
Contributor Author

Any estimate when this will get reviewed?

Copy link
Member

@retronym retronym left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks a lot a sorry about the slow review.

@retronym retronym merged commit 6989dd9 into scala:master Aug 23, 2017
@olafurpg olafurpg deleted the dotty2 branch August 23, 2017 07:36
@olafurpg
Copy link
Contributor Author

Thank you, no worries 😄

@retronym
Copy link
Member

After #38, I'm able to run benchmark the vector corpus with Dotty 0.2.0-RC1.

Trying better-files results in compile errors. scalap gives a compiler crash. Details. Known problems?

@retronym
Copy link
Member

Trying 0.3.0-RC1 now, seems the same.

@retronym
Copy link
Member

better-files compiles with 2.12.3 and Dottty after removing a few troublesome lines of code.

diff --git a/compilation/src/main/dotc/scala/tools/benchmark/BenchmarkDriver.scala b/compilation/src/main/dotc/scala/tools/benchmark/BenchmarkDriver.scala
index 6047a33..632210d 100644
--- a/compilation/src/main/dotc/scala/tools/benchmark/BenchmarkDriver.scala
+++ b/compilation/src/main/dotc/scala/tools/benchmark/BenchmarkDriver.scala
@@ -12,7 +12,7 @@ trait BenchmarkDriver extends BaseBenchmarkDriver {
       ctx.setSetting(ctx.settings.classpath,
                      depsClasspath.mkString(File.pathSeparator))
     }
-    ctx.setSetting(ctx.settings.migration, true)
+    ctx.setSetting(ctx.settings.migration, false)
     ctx.setSetting(ctx.settings.d, tempDir.getAbsolutePath)
     ctx.setSetting(ctx.settings.language, List("Scala2"))
     val compiler = new dotty.tools.dotc.Compiler
diff --git a/corpus/better-files/a45f905/File.scala b/corpus/better-files/a45f905/File.scala
index 8f46b00..876f5e1 100644
--- a/corpus/better-files/a45f905/File.scala
+++ b/corpus/better-files/a45f905/File.scala
@@ -264,7 +264,7 @@ class File private(val path: Path) {
   }
 
   def writeBytes(bytes: Iterator[Byte])(implicit openOptions: File.OpenOptions = File.OpenOptions.default): this.type = {
-    outputStream(openOptions).foreach(_.buffered write bytes)
+    ??? // outputStream(openOptions).foreach(x => x.buffered.write(bytes))
     this
   }
 
diff --git a/corpus/better-files/a45f905/Implicits.scala b/corpus/better-files/a45f905/Implicits.scala
index a9d26a6..ef36739 100644
--- a/corpus/better-files/a45f905/Implicits.scala
+++ b/corpus/better-files/a45f905/Implicits.scala
@@ -180,7 +180,7 @@ trait Implicits {
         f(resource)
       } finally {
         if (!isClosed) {
-          resource.close()
+          ???
           isClosed = true
         }
       }
@@ -207,7 +207,7 @@ trait Implicits {
       }
 
       def close() = try {
-        if (!isClosed) resource.close()
+        ??? // if (!isClosed) resource.close()
       } finally {
         isClosed = true
       }
@@ -218,7 +218,7 @@ trait Implicits {
         next
       } catch {
         case NonFatal(ex) =>
-          close()
+          ??? // close()
           throw ex
       }
 
diff --git a/corpus/better-files/a45f905/Scanner.scala b/corpus/better-files/a45f905/Scanner.scala
index 9295e54..ec7095c 100644
--- a/corpus/better-files/a45f905/Scanner.scala
+++ b/corpus/better-files/a45f905/Scanner.scala
@@ -57,7 +57,7 @@ object Scanner {
     */
   case class Config(delimiter: String, includeDelimiters: Boolean)(implicit val codec: Codec)
   object Config {
-    implicit val default = Config(delimiter = Delimiters.whitespaces, includeDelimiters = false)
+    implicit val default: Config = Config(delimiter = Delimiters.whitespaces, includeDelimiters = false)
 
     object Delimiters {
       val lines = "\n\r"
diff --git a/corpus/better-files/a45f905/package.scala b/corpus/better-files/a45f905/package.scala
index 8ef79e8..9edf2e4 100644
--- a/corpus/better-files/a45f905/package.scala
+++ b/corpus/better-files/a45f905/package.scala
@@ -17,7 +17,8 @@ package object files extends Implicits {
   @inline private[files] def when[A](condition: Boolean)(f: => A): Option[A] = if (condition) Some(f) else None
   @inline private[files] def repeat(n: Int)(f: => Unit): Unit = (1 to n).foreach(_ => f)
 
-  private[files] def produce[A](f: => A) = new {
+  private[files] def produce[A](f: => A): RichAny[A] = new RichAny(f)
+  private[files] class RichAny[A](f: => A) {
     def till(hasMore: => Boolean): Iterator[A] = new Iterator[A] {
       override def hasNext = hasMore
       override def next() = f

scalac compile times are is 0.65x that of 0.3.0-RC1. I understand the dotty build isn't able to eliminate debug tracing code that wraps a lot of core operations, this needs some search/replace. Anyway, it would be good to get an optimized build published so we can remove that noise.

@olafurpg
Copy link
Contributor Author

Dotty still fails to compile some Scala 2.x programs, most of the time it's due to known incompatibilities (missing type annotation for public implicit definition or scala.reflect macros). Sometimes it's just bugs.

I'm not involved in dotty performance optimizations, I think it's best you bring that up with the Dotty team to get a -optimize compiled release.

BTW, note that intellij-scala has a known issues when loading sbt projects with scalaVersion := "0.x" https://youtrack.jetbrains.com/oauth?state=%2Fissue%2FSCL-12237

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants